# coding=utf-8

"""This module contains python manipulators for palo objects"""

from datetime import datetime
from copy import deepcopy
from pypalo.basic import default
from pypalo.tools import sublist, strlist, arealize, meter, subdata, pacecounter, headfiller

from pypalo.requests.server import query as server
from pypalo.requests.database import query as database
from pypalo.requests.dimension import query as dimension
from pypalo.requests.element import query as element
from pypalo.requests.cube import query as cube
from pypalo.requests.cell import query as cell
from pypalo.requests.event import query as event
from pypalo.requests.rules import query as rules
from pypalo.requests.svs import query as svs

#query dictionary
query={}
query["server"]=server
query["database"]=database
query["dimension"]=dimension
query["element"]=element
query["cube"]=cube
query["cell"]=cell
query["event"]=event
query["rules"]=rules
query["svs"]=svs

class host:
	"""This is a host manipulator"""
	#beginning of class suite
	#init function
	def __init__(self, host=default["host"], port=default["port"]):
		self.host=host
		self.port=port
	
	#The following functions create class objects:
	def User(self, username=default["user"], password=default["password"], sid=default["sid"], timeinit=default["timeinit"], timeleft=default["timeleft"]):
		"""Function creates user class object"""
		#beginning of function suite
		#end of function suite
		return user(username, password, sid, timeinit, timeleft, self.host, self.port)
	
	#end of host class suite

class user(host):
	"""This is a user manipulator"""
	#beginning of class suite
	#init function
	def __init__(self, user=default["user"], password=default["password"], sid=default["sid"], timeinit=default["timeinit"], timeleft=default["timeleft"], host_ip=default["host"], port=default["port"]):
		#call parent init function with self arguments
		host.__init__(self, host_ip, port)
		#child methods
		self.user=user
		self.password=password
		self.sid=sid
		self.timeinit=timeinit
		self.timeleft=timeleft
        
		self.database=default["database"]
		self.dimension=default["dimension"]
		self.element=default["element"]
		self.cube=default["cube"]
		self.path=default["path"]
		self.rule=default["rule"]
	
	def state(self):
		"""This funtcion checks if sid is valid"""
		#beginning of function suite
		if self.sid and self.timeleft>(datetime.now()-self.timeinit).seconds:
			return True
		else:
			return False
		
	def newsid(self):
		"""This funtcion replaces old sid, timeinit, timeleft with new ones"""
		#beginning of function suite
		if self.state():
			self.disconnect()
			self.connect()
		else:
			self.connect()
		#end of function suite
		return
	
	def connect(self):
		"""This funtcion gets new sid"""
		#beginning of function suite
		self.sid=query["server"]["login"](self.host, self.port, user=self.user, password=self.password)[0][0]
		self.timeinit=datetime.now()
		self.timeleft=3595
		#end of function suite
		return

	def disconnect(self):
		"""This funtcion logouts and turns self.sid, self.timeinit, self.timeleft to None"""
		#beginning of function suite
		query["server"]["logout"](self.sid, self.host, self.port)
		self.sid=None
		self.timeinit=None
		self.timeleft=None
		#end of function suite
		return

	def getsid(self):
		"""This function validates sid, if not valid connects, finally returns self.sid"""
		#beginning of function suite
		if not self.state():
			self.connect()
		#end of function suite
		return self.sid

	#The following functions create class objects:
	def Server(self):
		"""Function creates server class object"""
		#beginning of function suite
		#end of function suite
		return server(self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	def Database(self, database_id=default["database"]):
		"""Function creates database class object"""
		#beginning of function suite
		database_id=database_id or self.database
		#end of function suite
		return database(database_id, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	def Dimension(self, dimension_id=default["dimension"], database_id=default["database"]):
		"""Function creates dimension class object"""
		#beginning of function suite
		dimension_id=dimension_id or self.dimension
		database_id=database_id or self.database
		#end of function suite
		return dimension(dimension_id, database_id, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	def Element(self, element_id=default["element"], dimension_id=default["dimension"], database_id=default["database"]):
		"""Function creates element class object"""
		#beginning of function suite
		element_id=element_id or self.element
		dimension_id=dimension_id or self.dimension
		database_id=database_id or self.database
		#end of function suite
		return element(element_id, dimension_id, database_id, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	def Cube(self, cube_id=default["cube"], database_id=default["database"]):
		"""Function creates cube class object"""
		#beginning of function suite
		cube_id=cube_id or self.cube
		database_id=database_id or self.database
		#end of function suite
		return cube(cube_id, database_id, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	def Cell(self, path=default["path"], cube_id=default["cube"], database_id=default["database"]):
		"""Function creates cell class object"""
		#beginning of function suite
		path=path or self.path
		cube_id=cube_id or self.cube
		database_id=database_id or self.database
		#end of function suite
		return cell(path, cube_id, database_id, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	def Rules(self, rule=default["rule"], cube_id=default["cube"], database_id=default["database"]):
		"""Function creates rules class object"""
		#beginning of function suite
		rule=rule or self.rule
		cube_id=cube_id or self.cube
		database_id=database_id or self.database
		#end of function suite
		return rules(rule, cube_id, database_id, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	def Svs(self):
		"""Function creates svs class object"""
		#beginning of function suite
		#end of function suite
		return svs(self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	#end of user class suite

class server(user):
	"""This is a server manipulator"""
	#beginning of class suite
	
	#init function
	def __init__(self, user_name=default["user"], password=default["password"], sid=default["sid"], timeinit=default["timeinit"], timeleft=default["timeleft"], host=default["host"], port=default["port"]):
		#parent init
		user.__init__(self, user_name, password, sid, timeinit, timeleft, host, port)
		#child methods
		
	#The following functions wrap PALO API requests:
	def databases(self, **keywords):
		"""Function returns list of databases\nPositional arguments: None\nKeyword arguments: show_normal, show_system, show_user_info\n
		"""
		#beginning of function suite
		#end of function suite
		return query["server"]["databases"](self.getsid(), self.host, self.port, **keywords)

	def info(self):
		"""Function returns server info\nPositional arguments: None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		#end of function suite
		return query["server"]["info"](self.host, self.port)

	def license(self):
		"""Function returns server license\nPositional arguments: None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		#end of function suite
		return query["server"]["license"](self.host, self.port)

	def load(self):
		"""Function loads server\nPositional arguments: None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		#end of function suite
		return query["server"]["load"](self.getsid(), self.host, self.port)

	def login(self, **keywords):
		"""Function returns sid\nPositional arguments: None\nKeyword arguments: user, password, extern_password\n
		"""
		#beginning of function suite
		#end of function suite
		return query["server"]["login"](self.host, self.port, **keywords)

	def logout(self, sid):
		"""Function logouts on server\nPositional arguments: None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		#end of function suite
		return query["server"]["logout"](sid, self.host, self.port)

	def save(self):
		"""Function saves server\nPositional arguments: None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		#end of function suite
		return query["server"]["save"](self.getsid(), self.host, self.port)

	def shutdown(self):
		"""Function shutdowns server\nPositional arguments: None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		#end of function suite
		return query["server"]["shutdown"](self.getsid(), self.host, self.port)

	#The following functions create class objects:
	def Database(self, database_id=default["database"]):
		"""Function creates database class object"""
		#beginning of function suite
		#end of function suite
		return database(database_id, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	#The following functions are server tools:
	def dictionary(self):
		"This function returns dictionary of server databases"
		#beginning of function suite
		databases=self.databases()
		result={}
		result['ids']={}
		result['names']={}
		for database in databases:
			result['ids'][database[0]]=database[1]
			result['names'][database[1]]=database[0]
		#end of function suite
		return result

	#end of server class suite

class database(user):
	"""This is a database manipulator"""
	#beginning of class suite
	
	#init function
	def __init__(self, database=default["database"], user_name=default["user"], password=default["password"], sid=default["sid"], timeinit=default["timeinit"], timeleft=default["timeleft"], host=default["host"], port=default["port"]):
		#parent init
		user.__init__(self, user_name, password, sid, timeinit, timeleft, host, port)
		#child methods
		self.database=database
	
	def cubes(self, database=None, **keywords):
		"""Function returns list of cubes\nPositional arguments: database=None\nKeyword arguments: show_normal, show_system, show_attribute, show_info, show_gputype\n
		"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return query["database"]["cubes"](database, self.getsid(), self.host, self.port, **keywords)
	
	#api requests:
	def create(self, new_name):
		"""Function creates a new database\nPositional arguments: new_name\nKeyword arguments: type (0=normal (default), 3=user info)\n
		"""
		#beginning of function suite
		#end of function suite
		return query["database"]["create"](new_name, self.getsid(), self.host, self.port, **keywords)

	def destroy(self, database=None):
		"""Function destroys database\nPositional arguments: database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return query["database"]["destroy"](database, self.getsid(), self.host, self.port)

	def dimensions(self, database=None, **keywords):
		"""Function returns list of cubes\nPositional arguments: None\nKeyword arguments: show_normal, show_system, show_attribute, show_info, database=None\n
		"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return query["database"]["dimensions"](database, self.getsid(), self.host, self.port, **keywords)

	def info(self, database=None):
		"""Function returns database info\nPositional arguments: database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return query["database"]["info"](database, self.getsid(), self.host, self.port)
	
	def load(self, database=None):
		"""Function loads database\nPositional arguments: database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return query["database"]["load"](database, self.getsid(), self.host, self.port)

	def rename(self, new_name, database=None, **keywords):
		"""Function renames database\nPositional arguments: new_name, database=None\nKeyword arguments: type (0=normal (default), 3=user info)\n
		"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return query["database"]["rename"](new_name, database, self.getsid(), self.host, self.port, **keywords)
		
	def save(self, database=None):
		"""Function saves database\nPositional arguments: database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return query["database"]["save"](database, self.getsid(), self.host, self.port)

	def unload(self, database=None):
		"""Function saves database\nPositional arguments: database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return query["database"]["unload"](database, self.getsid(), self.host, self.port)

	#The following functions create class objects:
	def Dimension(self, dimension_id=default["dimension"], database=None):
		"""Function creates dimension class object"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return dimension(dimension_id, database, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)
	
	def Cube(self, cube_id=default["cube"], database=None):
		"""Function creates cube class object"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return cube(cube_id, database, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	#The following functions are database tools:
	def dictionary(self):
		"This function returns dictionary of database cubes and dimensions"
		#beginning of function suite
		dimensions=self.dimensions()
		cubes=self.cubes()
		result={}
		result['dims']={'ids':{}}
		result['dims']['names']={}
		result['cubes']={'ids':{}}
		result['cubes']['names']={}
		for dimension in dimensions:
			result['dims']['ids'][dimension[0]]=dimension[1]
			result['dims']['names'][dimension[1]]=dimension[0]
		for cube in cubes:
			result['cubes']['ids'][cube[0]]=cube[1]
			result['cubes']['names'][cube[1]]=cube[0]
		#end of function suite
		return result

	#end of database class suite

class dimension(user):
	"""This is a dimension manipulator"""
	#beginning of class suite

	#def init
	def __init__(self, dimension=default["dimension"], database=default["database"], user_name=default["user"], password=default["password"], sid=default["sid"], timeinit=default["timeinit"], timeleft=default["timeleft"], host=default["host"], port=default["port"]):
		#parent init
		user.__init__(self, user_name, password, sid, timeinit, timeleft, host, port)
		#child methods
		self.database=database
		self.dimension=dimension

	#api requests:
	def clear(self, dimension=None, database=None):
		"""Function clears a dimension\nPositional arguments: dimension=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["dimension"]["clear"](dimension, database, self.getsid(), self.host, self.port)

	def create(self, new_name, database=None, **keywords):
		"""Function creates a new dimension\nPositional arguments: new_name, database=None\nKeyword arguments: type (0=normal (default), 3=user info)\n
		"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return query["dimension"]["create"](new_name, database, self.getsid(), self.host, self.port, **keywords)

	def cubes(self, dimension=None, database=None, **keywords):
		"""Function returns the list of cubes using a dimension\nPositional arguments: dimension=None, database=None\nKeyword arguments: show_normal, show_system, show_attribute, show_info, show_gputype\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["dimension"]["cubes"](dimension, database, self.getsid(), self.host, self.port, **keywords)

	def destroy(self, dimension=None, database=None):
		"""Function deletes a dimension\nPositional arguments: dimension=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["dimension"]["destroy"](dimension, database, self.getsid(), self.host, self.port)

	def element(self, position, dimension=None, database=None):
		"""Function returns one element at a given position\nPositional arguments: position, dimension=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["dimension"]["element"](position, dimension, database, self.getsid(), self.host, self.port)

	def elements(self, dimension=None, database=None, **keywords):
		"""Function returns the list of elements\nPositional arguments: dimension=None, database=None\nKeyword arguments: parent, limit\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["dimension"]["elements"](dimension, database, self.getsid(), self.host, self.port, **keywords)

	def info(self, dimension=None, database=None):
		"""Function returns dimension info\nPositional arguments: dimension=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["dimension"]["info"](dimension, database, self.getsid(), self.host, self.port)

	def rename(self, new_name, dimension=None, database=None):
		"""Function renames a dimension\nPositional arguments: new_name, dimension=None, database=None\nKeyword arguments: None
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["dimension"]["rename"](new_name, dimension, database, self.getsid(), self.host, self.port)
		
	def dfilter(self, cube, area, mode, dimension=None, database=None, **keywords):
		"""Function filters dimension elements\nPositional arguments: cube, area, mode, dimension=None, database=None\nKeyword arguments: condition, values\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["dimension"]["dfilter"](cube, area, mode, dimension, database, self.getsid(), self.host, self.port, **keywords)
		
	#The following functions create class objects:
	def Element(self, element=default["element"], dimension=None, database=None):
		"""Function creates element class object"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return element(element, dimension, database, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	#The following functions are server tools:
	def dictionary(self):
		"This function returns dictionary of dimension elements"
		#beginning of function suite
		elements=self.elements()
		result={}
		result['ids']={}
		result['names']={}
		for element in elements:
			result['ids'][element[0]]=element[1]
			result['names'][element[1]]=element[0]
		#end of function suite
		return result

	#end of element class suite

class element(user):
	"""This is an element manipulator"""
	#beginning of class suite
	
	#def init
	def __init__(self, element=default["element"], dimension=default["dimension"], database=default["database"], user_name=default["user"], password=default["password"], sid=default["sid"], timeinit=default["timeinit"], timeleft=default["timeleft"], host=default["host"], port=default["port"]):
		#parent init
		user.__init__(self, user_name, password, sid, timeinit, timeleft, host, port)
		#child methods
		self.database=database
		self.dimension=dimension
		self.element=element

	#api requests:
	def append(self, children, element=None, dimension=None, database=None, **keywords):
		"""Function appends the children of an consolidated element\nPositional arguments: children, element=None, dimension=None, database=None\nKeyword arguments: weights\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		element = element or self.element
		#end of function suite
		return query["element"]["append"](children, element, dimension, database, self.getsid(), self.host, self.port, **keywords)

	def create(self, new_name, type, dimension=None, database=None, **keywords):
		"""Function creates an element\nPositional arguments: new_name, type, dimension=None, database=None\nKeyword arguments: children, weights\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["element"]["create"](new_name, type, dimension, database, self.getsid(), self.host, self.port, **keywords)

	def create_bulk(self, name_elements, dimension=None, database=None, **keywords):
		"""Function creates elements\nPositional arguments: name_elements, dimension=None, database=None\nKeyword arguments: type, types, children, name_children, weights\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["element"]["create_bulk"](name_elements, dimension, database, self.getsid(), self.host, self.port, **keywords)

	def destroy(self, element=None, dimension=None, database=None):
		"""Function deletes an element\nPositional arguments: element=None, dimension=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		element = element or self.element
		#end of function suite
		return query["element"]["destroy"](element, dimension, database, self.getsid(), self.host, self.port)

	def destroy_bulk(self, dimension=None, database=None, **keywords):
		"""Function delete list of elements\nPositional arguments: dimension=None, database=None\nKeyword arguments: elements, name_elements\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["element"]["destroy_bulk"](dimension, database, self.getsid(), self.host, self.port, **keywords)
		
	def info(self, element=None, dimension=None, database=None):
		"""Function returns element info\nPositional arguments: element=None, dimension=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		element = element or self.element
		#end of function suite
		return query["element"]["info"](element, dimension, database, self.getsid(), self.host, self.port)

	def move(self, position, element=None, dimension=None, database=None):
		"""Function changes position of an element\nPositional arguments: position, element=None, dimension=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		element = element or self.element
		#end of function suite
		return query["element"]["move"](position, element, dimension, database, self.getsid(), self.host, self.port)

	def rename(self, new_name, element=None, dimension=None, database=None):
		"""Function renames an element\nPositional arguments: new_name, element=None, dimension=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		element = element or self.element
		#end of function suite
		return query["element"]["rename"](new_name, element, dimension, database, self.getsid(), self.host, self.port)

	def replace(self, dimension=None, database=None, **keywords):
		"""Function creates or updates an element\nPositional arguments: dimension=None, database=None\nKeyword arguments: element, name_element, type, children, weights\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["element"]["replace"](dimension, database, self.getsid(), self.host, self.port, **keywords)

	def replace_bulk(self, dimension=None, database=None, **keywords):
		"""Function creates or updates list of elements\nPositional arguments: dimension=None, database=None\nKeyword arguments: elements, name_elements, type, children, weights\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["element"]["replace_bulk"](dimension, database, self.getsid(), self.host, self.port, **keywords)

	#The following functions create class objects:
	#end of element class suite

class cube(user):
	"""This is a cube manipulator"""
	#beginning of class suite
	
	#def init
	def __init__(self, cube=default["cube"], database=default["database"], user_name=default["user"], password=default["password"], sid=default["sid"], timeinit=default["timeinit"], timeleft=default["timeleft"], host=default["host"], port=default["port"]):
		#parent init
		user.__init__(self, user_name, password, sid, timeinit, timeleft, host, port)
		#child methods
		self.database=database
		self.cube=cube

	#api requests:
	def clear(self, cube=None, database=None, **keywords):
		"""Function clears a cube\nPositional arguments: cube=None, database=None\nKeyword arguments: area, complete\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["clear"](cube, database, self.getsid(), self.host, self.port, **keywords)

	def commit(self, lock, cube=None, database=None):
		"""Function commits changes of a locked cube area\nPositional arguments: lock, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["commit"](lock, cube, database, self.getsid(), self.host, self.port)

	def create(self, new_name, dimensions, database=None, **keywords):
		"""Function creates a cube\nPositional arguments: new_name, dimensions, database=None\nKeyword arguments: type (0=normal (default), 3=user info)\n
		"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return query["cube"]["create"](new_name, dimensions, database, self.getsid(), self.host, self.port, **keywords)

	def destroy(self, cube=None, database=None):
		"""Function deletes a cube\nPositional arguments: cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["destroy"](cube, database, self.getsid(), self.host, self.port)

	def info(self, cube=None, database=None):
		"""Function returns cube info\nPositional arguments: cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["info"](cube, database, self.getsid(), self.host, self.port)

	def load(self, cube=None, database=None):
		"""Function loads cube\nPositional arguments: cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["load"](cube, database, self.getsid(), self.host, self.port)

	def lock(self, area, cube=None, database=None):
		"""Function locks a cube area\nPositional arguments: area, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["lock"](area, cube, database, self.getsid(), self.host, self.port)

	def locks(self, cube=None, database=None):
		"""Function lists the locked cube areas\nPositional arguments: , cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["locks"](cube, database, self.getsid(), self.host, self.port)

	def rename(self, new_name, cube=None, database=None):
		"""Function renames a cube\nPositional arguments: new_name, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["rename"](new_name, cube, database, self.getsid(), self.host, self.port)
		
	def rollback(self, lock, steps, cube=None, database=None):
		"""Function rollbacks changes of a locked cube area\nPositional arguments: lock, steps, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["rollback"](lock, steps, cube, database, self.getsid(), self.host, self.port)

	def rules(self, use_identifier, cube=None, database=None):
		"""Function lists the rules for a cube\nPositional arguments: use_identifier, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["rules"](use_identifier, cube, database, self.getsid(), self.host, self.port)

	def save(self, cube=None, database=None):
		"""Function saves cube data to disk\nPositional arguments: cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["save"](cube, database, self.getsid(), self.host, self.port)

	def unload(self, cube=None, database=None):
		"""Function unloads cube data from memory\nPositional arguments: cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["unload"](cube, database, self.getsid(), self.host, self.port)
		
	#The following functions create class objects:
	def Cell(self, path=default["path"], cube=None, database=None):
		"""Function creates dimension class object"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return cell(path, cube, database, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	def Rules(self, rule=default["rule"], cube=None, database=None):
		"""Function creates dimension class object"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return rules(rule, cube, database, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	#end of cube class suite

class cell(user):
	"""This is a cube manipulator"""
	#beginning of class suite
	
	#def init
	def __init__(self, path=default["path"], cube=default["cube"], database=default["database"], user_name=default["user"], password=default["password"], sid=default["sid"], timeinit=default["timeinit"], timeleft=default["timeleft"], host=default["host"], port=default["port"]):
		#parent init
		user.__init__(self, user_name, password, sid, timeinit, timeleft, host, port)
		#child methods
		self.database=database
		self.cube=cube
		self.path=path

	#api requests:
	def area(self, area, show_rule, show_lock_info, cube=None, database=None):
		"""Function shows values of cube cells\nPositional arguments: area, show_rule, show_lock_info, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cell"]["area"](area, show_rule, show_lock_info, cube, database, self.getsid(), self.host, self.port)

	def copy(self, path_to, path=None, cube=None, database=None, **keywords):
		"""Function copies a cell path to an other cell path\nPositional arguments: path_to, path=None, cube=None, database=None\nKeyword arguments: value\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		path = path or self.path
		#end of function suite
		return query["cell"]["copy"](path_to, path, cube, database, self.getsid(), self.host, self.port, **keywords)

	def drillthrough(self, mode, path=None, cube=None, database=None, **keywords):
		"""Function retrieves detailed data for a cube cell\nPositional arguments: mode, path=None, cube=None, database=None\nKeyword arguments: value\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		path = path or self.path
		#end of function suite
		return query["cell"]["drillthrough"](mode, path, cube, database, self.getsid(), self.host, self.port, **keywords)
		
	def export(self, cube=None, database=None, **keywords):
		"""Function exports values of cube cells\nPositional arguments: cube=None, database=None\nKeyword arguments: blocksize, path, area, condition, use_rules, base_only, skip_empty, type\n
		"""
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cell"]["export"](cube, database, self.getsid(), self.host, self.port, **keywords)
		
	def goalseek(self, path=None, cube=None, database=None, **keywords):
		"""Function puts value into cell and calculates values for sister cells in order to parents remain unchanged\nPositional arguments: path=None, cube=None, database=None\nKeyword arguments: value\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		path = path or self.path
		#end of function suite
		return query["cell"]["goalseek"](path, cube, database, self.getsid(), self.host, self.port, **keywords)

	def replace(self, value, path=None, cube=None, database=None, **keywords):
		"""Function sets or changes the value of cube cell\nPositional arguments: path=None, cube=None, database=None\nKeyword arguments: add, splash, event_processor\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		path = path or self.path
		#end of function suite
		return query["cell"]["replace"](value, path, cube, database, self.getsid(), self.host, self.port, **keywords)

	def replace_bulk(self, paths, values, cube=None, database=None, **keywords):
		"""Function sets or changes the value of cube cells\nPositional arguments: cube=None, database=None\nKeyword arguments: add, splash, event_processor\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cell"]["replace_bulk"](paths, values, cube, database, self.getsid(), self.host, self.port, **keywords)

	def value(self, show_rule, show_lock_info, path=None, cube=None, database=None):
		"""Function returns the value of a cube cell\nPositional arguments: show_rule, show_lock_info, path=None, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		path = path or self.path
		#end of function suite
		return query["cell"]["value"](show_rule, show_lock_info, path, cube, database, self.getsid(), self.host, self.port)

	def values(self, paths, show_rule, show_lock_info, cube=None, database=None):
		"""Function returns the values of a cube cells\nPositional arguments: show_rule, show_lock_info, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cell"]["values"](paths, show_rule, show_lock_info, cube, database, self.getsid(), self.host, self.port)

	#The following functions are cell tools

	def extract(self, conditions={}, output=None, params=[0,1,1,0], cube=None, database=None):
		"This function returns values of database cube for {dim_id:[elems_ids]}\nParams: [use_rules, base_only, skip_empty, type]\nOutput: list of [type, exists, value, path] lists"
		#beginning of function suite
		
		database = database or self.database
		cube = cube or self.cube
		
		dimensions = query["cube"]["info"](cube, database, self.getsid(), self.host, self.port)[0][3]
		
		area=arealize(conditions, dimensions)
		
		result=self.export(cube, database, area=area, use_rules=params[0], base_only=params[1], skip_empty=params[2], type=params[3])
		
		while result[-1][0]<result[-1][1]:
			for item in result[:-1]:
				item=sublist(item, output)
				if len(item)==1:
					yield item[0]
				else:
					yield item
			result=self.export(cube, database, area=area, use_rules=params[0], base_only=params[1], skip_empty=params[2], type=params[3], path=','.join(strlist(result[-2][3])))

		if result[-1][0]>=result[-1][1]:
			for item in result[:-1]:
				item=sublist(item, output)
				if len(item)==1:
					yield item[0]
				else:
					yield item
		#end of function suite
	
	#The following functions create class objects:
	def Nda(self, conditions={}, params=[0,1,1,0], cube=None, database=None):
		"This function returns nda class object"
		#beginning of function suite
		
		database = database or self.database
		cube = cube or self.cube
		dimensions = query["cube"]["info"](cube, database, self.getsid(), self.host, self.port)[0][3]
		
		#Формируются генераторы данных куба
		typevalue=self.extract(conditions, [0,2], params, cube, database)
		coord=self.extract(conditions, [3], params, cube, database)
		valuecoord=self.extract(conditions, [2,3], params, cube, database)
		
		#Формируется метрика куба
		metrics = meter(typevalue, coord, valuecoord, dimensions)
		
		#К метрике куба добавляются словари:
		metrics["dictionary"]={}
		
		s_dict_iter=self.Server().dictionary()
		s_dict={"db":self.Server().dictionary()}
		for item in s_dict_iter["ids"]:
			if item != database:
				del s_dict["db"]["ids"][item]
		for item in s_dict_iter["names"]:
			if s_dict_iter["names"][item] != database:
				del s_dict["db"]["names"][item]
		
		db_dict_iter=self.Database().dictionary()
		db_dict=self.Database().dictionary()
		for item in db_dict_iter["dims"]["ids"]:
			if item not in dimensions:
				del db_dict["dims"]["ids"][item]
		for item in db_dict_iter["dims"]["names"]:
			if db_dict_iter["dims"]["names"][item] not in dimensions:
				del db_dict["dims"]["names"][item]
		for item in db_dict_iter["cubes"]["ids"]:
			if item != cube:
				del db_dict["cubes"]["ids"][item]
		for item in db_dict_iter["cubes"]["names"]:
			if db_dict_iter["cubes"]["names"][item] != cube:
				del db_dict["cubes"]["names"][item]
				
		el_dict={"elems":{}}
		for dim in metrics["dims"]:
			el_dict["elems"][dim]=self.Dimension(dim).dictionary()
		
		metrics["dictionary"].update(s_dict)
		metrics["dictionary"].update(db_dict)
		metrics["dictionary"].update(el_dict)

		#Функция возвращает экземпляр класса nda
		return nda(database, cube, conditions, params, metrics["dims"], metrics["dims_nda"], metrics["elems"], metrics["elems_filled"], metrics["length"], metrics["width"], metrics["width_nda"], metrics["shape"], metrics["shape_nda"], metrics["type"], metrics["null"], metrics["data"], metrics["dictionary"])
    
            
            
            
	def lol(self, columns, rows, filter, conditions, zeros=True, names=True, empty=None):
		"This function generates list of lists from cube cells"
		#beginning of function suite

        #Для каждого измерения-фильтра:
		for item in filter:
			#Если в условиях ему не соответствует лист длиной в один элемент
			if not(type(conditions[item])==list and len(conditions[item])==1):
				#Вызывается исключение
				raise Exception("Dim: "+item+". Condition for the filter dimension must be a list of one element")
        
		if names:
			columns_names = columns
			columns = []
			rows_names = rows
			rows = []
			filter_names = filter
			filter = []
			conditions_names = deepcopy(conditions)
			conditions = {}
        
			db_dict = self.Database().dictionary()
                
			for column_name in columns_names:
				columns += [db_dict['dims']['names'][column_name]]
        
			for row_name in rows_names:
				rows += [db_dict['dims']['names'][row_name]]
        
			for filter_name in filter_names:
				filter += [db_dict['dims']['names'][filter_name]]

			for item in conditions_names:
				dim = db_dict['dims']['names'][item]
				dim_dict = self.Dimension(dim).dictionary()
				conditions[dim]=[]
				for subitem in conditions_names[item]:
					#print(subitem)
					conditions[dim]+=[dim_dict['names'][subitem]]
        
		#Создается объект класса nda
		n=self.Nda(conditions, [0,0,1,0]).subnda()
		#print(list(n.dictionary['elems'][17]['ids']))
		#Проверяется все ли измерения распределены между колонками, строками и фильтром
		#Для каждого измерения объекта nda
		for dim in n.dims:
			#Если измерения нет в сумме списков колонок, строк и фильтра
			if dim not in columns + rows + filter:
				#Вызывается исключение
				raise Exception("Dim: "+dim+". Dimension neither in columns nor rows nor filter list")
    
		#Если подавление нулей истинно
		if zeros:
			#переменной helems присваивается словарь элементов
			helems=n.elems
		#Иначе
		else:
			#переменной helems присваивается словарь заполненных элементов
			helems=n.elems_filled
    
		#Формируется словарь шагов для колонок
		cpaces=pacecounter(columns, helems)
		#Формируется словарь элементов колонок
		celems=headfiller(columns, helems, cpaces)
		#Переменной clen присваивается длина списка измерений-колонок
		clen=len(columns)
    
		#Формируется словарь шагов для строк
		rpaces=pacecounter(rows, helems)
		#Формируется словарь элементов строк
		relems=headfiller(rows, helems, rpaces)
		#Переменной rlen присваивается длина списка измерений-строк
		rlen=len(rows)
    
		#Создается пустой список результат
		result=[]
    
		#I. Добавляются заголовки колонок
		#Для каждого измерения-колонки:
		for column in columns:
			#Создается пустой временный список:
			temp=[]
			#В него добавляется список пустых значений соответствующий заголовкам строк
			temp+=[empty]*rlen
			#Для каждого элемента в списке элементов измерения-колонки:
			for elem in celems[column]:
				#Во временный список добавляется имя элемента
				temp+=[n.dictionary['elems'][column]['ids'][elem]]
			result+=[temp]
    
		#II. Добавляются заголовки строк и значения таблицы
		#Для каждого номера строки значений:
		for x in range(rpaces['len']):
			#Создается пустой временный список
			temp=[]
			#Для каждого номера колонки таблицы:
			for y in range(rlen+cpaces['len']):
				#Если номер колонки в ряду номеров строк:
				if y in range(rlen):
					#Во временный список добавляется заголовок соответствующей строки
					temp+=[n.dictionary['elems'][rows[y]]['ids'][relems[rows[y]][x]]]
				#Иначе
				else:
					#Создается пустой словарь координат соответствующей ячейки куба
					cell={}
					#Для каждого измерения-колонки
					for column in columns:
						#В словарь добавляется соответствующий номер элемента
						cell[column]=[celems[column][y-rlen]]
					#Для каждого измерения-строки
					for row in rows:
						#В словарь добавляется соответствующий номер элемента
						cell[row]=[relems[row][x]]
						#Во временный список добавляется значение ячейки куба
					temp+=[n.subnda(cell).data]
			#В результат добавляется временный список
			result+=[temp]
		#Функция возвращается list of list (lol)
		return result

	#end of cell class suite

class event(host):
	"""This is an event manipulator"""
	#beginning of class suite
	
	#def init
	def __init__(self, host_ip=default["host"], port=default["port"]):
		#parent init
		host.__init__(self, host_ip, port)
		#child methods

	#api requests:
	def begin(self, sid, source, event):
		"""Function starts an event\nPositional arguments: sid, source, event\nKeyword arguments: None\n
		"""
		#beginning of function suite
		#end of function suite
		return query["event"]["begin"](sid, source, event, self.host, self.port)

	def end(self, sid):
		"""Function ends an event\nPositional arguments: sid\nKeyword arguments: None\n
		"""
		#beginning of function suite
		#end of function suite
		return query["event"]["end"](sid, self.host, self.port)

	#other groups api requests:
	#The following functions create class objects:

	#end of event class suite

class rules(user):
	"""This is a rules manipulator"""
	#beginning of class suite

	#def init
	def __init__(self, rule=default["rule"], cube=default["cube"], database=default["database"], user_name=default["user"], password=default["password"], sid=default["sid"], timeinit=default["timeinit"], timeleft=default["timeleft"], host=default["host"], port=default["port"]):
		#parent init
		user.__init__(self, user_name, password, sid, timeinit, timeleft, host, port)
		#child methods
		self.database=database
		self.cube=cube
		self.rule=rule

	#api requests:
	def create(self, definition, activate, external_identifier, comment, use_identifier, cube=None, database=None):
		"""Function creates a new enterprise rule for a cube\nPositional arguments: definition, activate, external_identifier, comment, use_identifier, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["rules"]["create"](definition, activate, external_identifier, comment, use_identifier, cube, database, self.getsid(), self.host, self.port)
		
	def destroy(self, rule=None, cube=None, database=None):
		"""Function removes an enterprise rule from a cube\nPositional arguments: rule=None, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		rule = rule or self.rule
		#end of function suite
		return query["rules"]["destroy"](rule, cube, database, self.getsid(), self.host, self.port)

	def functions(self):
		"""Function lists available functions\nPositional arguments: None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		#end of function suite
		return query["rules"]["functions"](self.getsid(), self.host, self.port)

	def info(self, use_identifier, rule=None, cube=None, database=None):
		"""Function returns information about a defined rule\nPositional arguments: use_identifier, rule=None, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		rule = rule or self.rule
		#end of function suite
		return query["rules"]["info"](use_identifier, rule, cube, database, self.getsid(), self.host, self.port)

	def modify(self, definition, activate, external_identifier, comment, use_identifier, rule=None, cube=None, database=None):
		"""Function modifies an enterprise rule for a cube\nPositional arguments: definition, activate, external_identifier, comment, use_identifier, rule=None, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		rule = rule or self.rule
		#end of function suite
		return query["rules"]["modify"](definition, activate, external_identifier, comment, use_identifier, rule, cube, database, self.getsid(), self.host, self.port)
		
	def parse(self, definition, **keywords):
		"""Function parse an enterprise rule\nPositional arguments: definition\nKeyword arguments: database, cube, functions\n
		"""
		#beginning of function suite
		#end of function suite
		return query["rules"]["parse"](definition, self.getsid(), self.host, self.port, **keywords)

	#other groups api requests:
	#The following functions create class objects:
	
	#end of rule class suite

class svs(user):
	"""This is a svs manipulator"""
	#beginning of class suite
	
	#import functions from rules module
	
	
	#def init
	def __init__(self, user_name=default["user"], password=default["password"], sid=default["sid"], timeinit=default["timeinit"], timeleft=default["timeleft"], host=default["host"], port=default["port"]):
		#parent init
		user.__init__(self, user_name, password, sid, timeinit, timeleft, host, port)
		#child methods
	
	#api requests:
	def info(self):
		"""Function returns information about Supervision Server\nPositional arguments: None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		#end of function suite
		return query["svs"]["info"](self.getsid(), self.host, self.port)

	#other groups api requests:
	#The following functions create class objects:

	#end of svs class suite
	
class nda:
	"This is a manipulator for nda from olap"
	#beginning of class suite
	def __init__(self, database, cube, conditions, params, dims, dims_nda, elems, elems_filled, length, width, width_nda, shape, shape_nda, type, null, data, dictionary):
		self.database=database
		self.cube=cube
		self.conditions=conditions
		self.params=params
		self.dims=dims
		self.dims_nda=dims_nda
		self.elems=elems
		self.elems_filled=elems_filled
		self.length=length
		self.width=width
		self.width_nda=width_nda
		self.shape=shape
		self.shape_nda=shape_nda
		self.type=type
		self.null=null
		self.data=data
		self.dictionary=dictionary
		
	def subnda(self, new_con={}, reduce=True):
		"This function returns new nda object where conditions={dim:elems} is satisfied and single element dimension is reduced if reduce is True"
		#beginning of function suite
		#Создается словарь новых атрибутов в соответствии с условиями выборки
		new=subdata(new_con, deepcopy(self.conditions), deepcopy(self.dims), deepcopy(self.dims_nda), deepcopy(self.elems), self.null, deepcopy(self.data), reduce)
		#print(self.dims)
		#Создается новый объект класса nda с измененными атрибутами
		result=nda(self.database, self.cube, new["conditions"], self.params, self.dims, new["dims_nda"], new["elems"], new["elems_filled"], self.length, self.width, new["width_nda"], new["shape"], new["shape_nda"], self.type, self.null, new["data"], self.dictionary)
		#end of function suite
		#Функция возвращает новый объект nda
		return result
		
	#Slice or dice should be chosen (slicing or dicing) and dictionaries bugs. n.Nda() inherits last call conditions
		
		
	#end of nda class suite